//===--- ValueWitness.def - Value witness x-macros --------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// X-macro definition file for value witness tables.
//
//===----------------------------------------------------------------------===//

// This file is "parameterized" in the sense that exactly one of the
// following macros *must* be defined:

/// WANT_ALL_VALUE_WITNESSES
///   Define this to expand all value witnesses, not just the ones from
///   a specific category.
#if defined(WANT_ALL_VALUE_WITNESSES)
#undef WANT_ALL_VALUE_WITNESSES
#define WANT_REQUIRED_VALUE_WITNESSES         1
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 1
#define WANT_ENUM_VALUE_WITNESSES             1

/// WANT_ONLY_REQUIRED_VALUE_WITNESSES
///   Define this to expand only the required value witnesses.
#elif defined(WANT_ONLY_REQUIRED_VALUE_WITNESSES)
#undef WANT_ONLY_REQUIRED_VALUE_WITNESSES
#define WANT_REQUIRED_VALUE_WITNESSES         1
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 0
#define WANT_ENUM_VALUE_WITNESSES             0

/// WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
///   Define this to expand only the extra-inhabitant value witnesses.
#elif defined(WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES)
#undef WANT_ONLY_EXTRA_INHABITANT_VALUE_WITNESSES
#define WANT_REQUIRED_VALUE_WITNESSES         0
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 1
#define WANT_ENUM_VALUE_WITNESSES             0

/// WANT_ONLY_ENUM_VALUE_WITNESSES
///   Define this to expand only the enum value witnesses.
#elif  defined(WANT_ONLY_ENUM_VALUE_WITNESSES)
#undef  WANT_ONLY_ENUM_VALUE_WITNESSES
#define WANT_REQUIRED_VALUE_WITNESSES         0
#define WANT_EXTRA_INHABITANT_VALUE_WITNESSES 0
#define WANT_ENUM_VALUE_WITNESSES             1

/// WANT_REQUIRED_VALUE_WITNESSES
/// WANT_EXTRA_INHABITANT_VALUE_WITNESSES
/// WANT_ENUM_VALUE_WITNESSES
///   Define all of these to control exactly what to expand.
#else
#if !defined(WANT_REQUIRED_VALUE_WITNESSES) ||  !defined(WANT_EXTRA_INHABITANT_VALUE_WITNESSES) || !defined(WANT_ENUM_VALUE_WITNESSES)
#error failed to define a WANT macro; possible typo?
#endif
#endif

/// VALUE_WITNESS(lowerId, upperId)
///   A fallback called for value witnesses if either of DATA_VALUE_WITNESS or
///   FUNCTION_VALUE_WITNESS is not defined.

/// FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypeList)
///   A function value witness.  Types will be defined in terms of the
///   following macros:
///     MUTABLE_VALUE_TYPE - a pointer to a mutable opaque value
///     IMMUTABLE_VALUE_TYPE - a pointer to an immutable opaque value
///     MUTABLE_BUFFER_TYPE - a pointer to a fixed-size value buffer
///     IMMUTABLE_BUFFER_TYPE - a pointer to an immutable fixed-size buffer
///     TYPE_TYPE - a pointer to type metadata
///     SIZE_TYPE - size_t
///     INT_TYPE - int
///     VOID_TYPE - void
///   Defaults to VALUE_WITNESS.
///   FIXME: The 'copy' witnesses should be using immutable types but aren't.
#ifndef FUNCTION_VALUE_WITNESS
#define FUNCTION_VALUE_WITNESS(lowerId, upperId, returnType, paramTypes) \
  VALUE_WITNESS(lowerId, upperId)
#endif

/// DATA_VALUE_WITNESS(lowerId, upperId, type)
///   A non-function value witness.  Types are specified as for
///   FUNCTION_VALUE_WITNESS
///   Defaults to VALUE_WITNESS.
#ifndef DATA_VALUE_WITNESS
#define DATA_VALUE_WITNESS(lowerId, upperId, type) \
  VALUE_WITNESS(lowerId, upperId)
#endif

/// Begin a range of value witnesses.  This will be expanded immediately
/// after the first value in the range, whose ID will be upperId.
/// Range expansions do not interact well with the use of WANT_ONLY_*.
#ifndef BEGIN_VALUE_WITNESS_RANGE
#define BEGIN_VALUE_WITNESS_RANGE(rangeId, upperId)
#endif

/// End a range of value witnesses.  This will be expanded immediately
/// after the last value in the range, whose ID will be upperId.
/// Range expansions do not interact well with the use of WANT_ONLY_*.
#ifndef END_VALUE_WITNESS_RANGE
#define END_VALUE_WITNESS_RANGE(rangeId, upperId)
#endif

#if WANT_REQUIRED_VALUE_WITNESSES

///   T *(*initializeBufferWithCopyOfBuffer)(B *dest, B *src, M *self);
/// Given an invalid buffer, initialize it as a copy of the
/// object in the source buffer.
FUNCTION_VALUE_WITNESS(initializeBufferWithCopyOfBuffer,
                       InitializeBufferWithCopyOfBuffer,
                       MUTABLE_VALUE_TYPE,
                       (MUTABLE_BUFFER_TYPE, MUTABLE_BUFFER_TYPE, TYPE_TYPE))

BEGIN_VALUE_WITNESS_RANGE(ValueWitness,
                          InitializeBufferWithCopyOfBuffer)
BEGIN_VALUE_WITNESS_RANGE(RequiredValueWitness,
                          InitializeBufferWithCopyOfBuffer)
BEGIN_VALUE_WITNESS_RANGE(RequiredValueWitnessFunction,
                          InitializeBufferWithCopyOfBuffer)

///   void (*destroy)(T *object, witness_t *self);
///
/// Given a valid object of this type, destroy it, leaving it as an
/// invalid object.  This is useful when generically destroying
/// an object which has been allocated in-line, such as an array,
/// struct, or tuple element.
FUNCTION_VALUE_WITNESS(destroy,
                       Destroy,
                       VOID_TYPE,
                       (MUTABLE_VALUE_TYPE, TYPE_TYPE))

///   T *(*initializeWithCopy)(T *dest, T *src, M *self);
///
/// Given an invalid object of this type, initialize it as a copy of
/// the source object.  Returns the dest object.
FUNCTION_VALUE_WITNESS(initializeWithCopy,
                       InitializeWithCopy,
                       MUTABLE_VALUE_TYPE,
                       (MUTABLE_VALUE_TYPE, MUTABLE_VALUE_TYPE, TYPE_TYPE))

///   T *(*assignWithCopy)(T *dest, T *src, M *self);
///
/// Given a valid object of this type, change it to be a copy of the
/// source object.  Returns the dest object.
FUNCTION_VALUE_WITNESS(assignWithCopy,
                       AssignWithCopy,
                       MUTABLE_VALUE_TYPE,
                       (MUTABLE_VALUE_TYPE, MUTABLE_VALUE_TYPE, TYPE_TYPE))

///   T *(*initializeWithTake)(T *dest, T *src, M *self);
///
/// Given an invalid object of this type, initialize it by taking
/// the value of the source object.  The source object becomes
/// invalid.  Returns the dest object.
FUNCTION_VALUE_WITNESS(initializeWithTake,
                       InitializeWithTake,
                       MUTABLE_VALUE_TYPE,
                       (MUTABLE_VALUE_TYPE, MUTABLE_VALUE_TYPE, TYPE_TYPE))

///   T *(*assignWithTake)(T *dest, T *src, M *self);
///
/// Given a valid object of this type, change it to be a copy of the
/// source object.  The source object becomes invalid.  Returns the
/// dest object.
FUNCTION_VALUE_WITNESS(assignWithTake,
                       AssignWithTake,
                       MUTABLE_VALUE_TYPE,
                       (MUTABLE_VALUE_TYPE, MUTABLE_VALUE_TYPE, TYPE_TYPE))

///   T *(*initializeBufferWithTakeOfBuffer)(B *dest, B *src, M *self);
/// Given an invalid buffer, initialize it by taking the value out of
/// the source buffer.
FUNCTION_VALUE_WITNESS(initializeBufferWithTakeOfBuffer,
                       InitializeBufferWithTakeOfBuffer,
                       MUTABLE_VALUE_TYPE,
                       (MUTABLE_BUFFER_TYPE, MUTABLE_BUFFER_TYPE, TYPE_TYPE))

END_VALUE_WITNESS_RANGE(RequiredValueWitnessFunction,
                        InitializeBufferWithTakeOfBuffer)

///   size_t size;
///
/// The required storage size of a single object of this type.
DATA_VALUE_WITNESS(size,
                   Size,
                   SIZE_TYPE)

BEGIN_VALUE_WITNESS_RANGE(TypeLayoutWitness,
                          Size)

BEGIN_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
                          Size)

///   size_t flags;
///
/// The ValueWitnessAlignmentMask bits represent the required
/// alignment of the first byte of an object of this type, expressed
/// as a mask of the low bits that must not be set in the pointer.
/// This representation can be easily converted to the 'alignof'
/// result by merely adding 1, but it is more directly useful for
/// performing dynamic structure layouts, and it grants an
/// additional bit of precision in a compact field without needing
/// to switch to an exponent representation.
///
/// The ValueWitnessIsNonPOD bit is set if the type is not POD.
///
/// The ValueWitnessIsNonInline bit is set if the type cannot be
/// represented in a fixed-size buffer.
///
/// The Enum_HasExtraInhabitants bit is set if the type's binary
/// representation has "extra inhabitants" that do not form valid values of
/// the type, and the value witness table contains the ExtraInhabitantWitness
/// entries.
///
/// The Enum_HasSpareBits bit is set if the type's binary representation
/// has unused bits.
///
/// The HasEnumWitnesses bit is set if the type is an enum type.
DATA_VALUE_WITNESS(flags,
                   Flags,
                   SIZE_TYPE)

///   size_t stride;
///
/// The required size per element of an array of this type. It is at least
/// one, even for zero-sized types, like the empty tuple.
DATA_VALUE_WITNESS(stride,
                   Stride,
                   SIZE_TYPE)

END_VALUE_WITNESS_RANGE(RequiredTypeLayoutWitness,
                        Stride)

END_VALUE_WITNESS_RANGE(RequiredValueWitness,
                        Stride)

#endif /* WANT_REQUIRED_VALUE_WITNESSES */

#if WANT_EXTRA_INHABITANT_VALUE_WITNESSES

// The following value witnesses are conditionally present based on
// the Enum_HasExtraInhabitants bit of the flags.

///   size_t extraInhabitantFlags;
///
/// These bits are always present if the extra inhabitants witnesses are:
///
/// - The NumExtraInhabitantsMask bits contain the number of extra
///   inhabitants of the type representation.
///
/// If the Enum_HasSpareBits flag is set in the value witness flags, these
/// additional flags are available:
///
/// - The NumSpareBitsMask bits contain the number of (host-endian) contiguous
///   spare bits in the type representation.
/// - The SpareBitsShiftMask bits contain the (host-endian) bit offset of the
///   lowest spare bit.
DATA_VALUE_WITNESS(extraInhabitantFlags,
                   ExtraInhabitantFlags,
                   SIZE_TYPE)

BEGIN_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitness,
                          ExtraInhabitantFlags)

END_VALUE_WITNESS_RANGE(TypeLayoutWitness,
                        ExtraInhabitantFlags)

///   void (*storeExtraInhabitant)(T *obj, int index, M *self);
///
/// Given an invalid object of this type, store the representation of an
/// extra inhabitant of the type. The object will remain invalid, because
/// an extra inhabitant is by definition an invalid representation of the
/// type. index must be less than numExtraInhabitants.
FUNCTION_VALUE_WITNESS(storeExtraInhabitant,
                       StoreExtraInhabitant,
                       VOID_TYPE,
                       (MUTABLE_VALUE_TYPE, INT_TYPE, TYPE_TYPE))

BEGIN_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitnessFunction,
                          StoreExtraInhabitant)

///   int (*getExtraInhabitantIndex)(T *obj, M *self);
///
/// Given an invalid object of this type with an extra inhabitant
/// representation, returns the index of the extra inhabitant representation.
/// Returns -1 if the object is a valid value of the type. If non-negative,
/// the return value is the same index that can be passed to
/// storeExtraInhabitant to reproduce the representation.
FUNCTION_VALUE_WITNESS(getExtraInhabitantIndex,
                       GetExtraInhabitantIndex,
                       INT_TYPE,
                       (IMMUTABLE_VALUE_TYPE, TYPE_TYPE))

END_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitnessFunction,
                        GetExtraInhabitantIndex)

END_VALUE_WITNESS_RANGE(ExtraInhabitantValueWitness,
                        GetExtraInhabitantIndex)

#endif /* WANT_EXTRA_INHABITANT_VALUE_WITNESSES */

#if WANT_ENUM_VALUE_WITNESSES

// The following value witnesses are conditionally present if the witnessed
// type is an enum.

///   int (*getEnumTag)(T *obj, M *self);
///
/// Given a valid object of this enum type, extracts the tag value indicating
/// which case of the enum is inhabited. Returned values are in the range
/// [-ElementsWithPayload..ElementsWithNoPayload-1].
FUNCTION_VALUE_WITNESS(getEnumTag,
                       GetEnumTag,
                       INT_TYPE,
                       (IMMUTABLE_VALUE_TYPE, TYPE_TYPE))

BEGIN_VALUE_WITNESS_RANGE(EnumValueWitness,
                          GetEnumTag)

///   void (*destructiveProjectEnumData)(T *obj, M *self);
/// Given a valid object of this enum type, destructively extracts the
/// associated payload.
FUNCTION_VALUE_WITNESS(destructiveProjectEnumData,
                       DestructiveProjectEnumData,
                       VOID_TYPE,
                       (MUTABLE_VALUE_TYPE, TYPE_TYPE))

///   void (*destructiveInjectEnumTag)(T *obj, int tag, M *self);
/// Given an enum case tag and a valid object of case's payload type,
/// destructively inserts the tag into the payload. The given tag value
/// must be in the range [-ElementsWithPayload..ElementsWithNoPayload-1].
FUNCTION_VALUE_WITNESS(destructiveInjectEnumTag,
                       DestructiveInjectEnumTag,
                       VOID_TYPE,
                       (MUTABLE_VALUE_TYPE, INT_TYPE, TYPE_TYPE))

END_VALUE_WITNESS_RANGE(EnumValueWitness,
                        DestructiveInjectEnumTag)

END_VALUE_WITNESS_RANGE(ValueWitness,
                        DestructiveInjectEnumTag)

#endif /* WANT_ENUM_VALUE_WITNESSES */

#undef MUTABLE_VALUE_TYPE
#undef IMMUTABLE_VALUE_TYPE
#undef MUTABLE_BUFFER_TYPE
#undef IMMUTABLE_BUFFER_TYPE
#undef TYPE_TYPE
#undef SIZE_TYPE
#undef INT_TYPE
#undef VOID_TYPE

#undef END_VALUE_WITNESS_RANGE
#undef BEGIN_VALUE_WITNESS_RANGE
#undef DATA_VALUE_WITNESS
#undef FUNCTION_VALUE_WITNESS
#undef VALUE_WITNESS
#undef ENUM_VALUE_WITNESS
#undef EXTRA_INHABITANT_VALUE_WITNESS
#undef NON_REQUIRED_VALUE_WITNESS
#undef REQUIRED_VALUE_WITNESS
#undef WANT_ENUM_VALUE_WITNESSES
#undef WANT_EXTRA_INHABITANT_VALUE_WITNESSES
#undef WANT_REQUIRED_VALUE_WITNESSES
